import {getProvinceHistory, getProvincePredict, Province} from "@/api/province.ts";
import MapView from "@arcgis/core/views/MapView";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
import china from "@/assets/china.json"
import Graphic from "@arcgis/core/Graphic";
import Polygon from "@arcgis/core/geometry/Polygon";
import ArcGISMap from "@arcgis/core/Map.js";
import ColumnChartMediaInfo from "@arcgis/core/popup/content/ColumnChartMediaInfo";
import Color from "@arcgis/core/Color";
import Point from "@arcgis/core/geometry/Point";
import SimpleMarkerSymbol from "@arcgis/core/symbols/SimpleMarkerSymbol";
import {Data, getStationHistory, getStationPredict} from "@/api/airQuality.ts";
import location from "@/assets/location.ts";
import * as echarts from 'echarts';
import {EChartsType} from 'echarts';
import {Area, getAreaHistory, getAreaPredict} from "@/api/area.ts";
import {Common} from "@/utils/common.ts";
import {quality} from "@/api/common.ts";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
import SimpleFillSymbol from "@arcgis/core/symbols/SimpleFillSymbol";
import MediaContentProperties = __esri.MediaContentProperties;
import FieldInfoProperties = __esri.FieldInfoProperties;
import {Base, Quality} from "@/api/baseQuality.ts";

export enum RenderType {
    AQI = "aqi",
    PM2_5 = "pm25",
    PM10 = "pm10",
    SO2 = "so2",
    NO2 = "no2",
    CO = "co",
    O3 = "o3",
}

export enum RenderChange {
    TimeChange = 0,
    SizeChange = 1,
    TargetChange = 2,
    FieldChange = 3
}

export interface Attribute {
    aqi: number;
    pm25: number;
    pm10: number;
    so2: number;
    no2: number;
    co: number;
    o3: number;
    level: number;
    type: number;
    title: string;
    color: string;
    id: number;
}

export enum RenderTypeName {
    province = 0,
    area = 1,
    station = 2
}

interface GradeObject {

    /**
     * 污染物等级
     */
    level: number;

    /**
     *  污染物等级颜色
     */
    color: string;

    /**
     *  污染物等级名称
     */
    label: string;

    /**
     *  污染物等级左阈值
     */
    valueLeft?: number;

    /**
     * 污染物等级又阈值
     */
    valueRight?: number;
}

export interface Render {
    map: __esri.Map;
    view: MapView;
    graphicLayer: GraphicsLayer;
    zoom: number;
    type: number;

    render(data: Quality[], type: RenderType): void;

    getMedia(): MediaContentProperties;

    getFieldInfo(): FieldInfoProperties[];

    reRender();

    svgRender(graphic: Graphic, size: number): void;

    resolveGrade(data: Quality, type: RenderType): GradeObject;
}

/**
 * 地图渲染
 */
class BaseRender implements Render {
    graphicLayer: GraphicsLayer;
    map: ArcGISMap;
    view: MapView;
    zoom: number;
    static featureLayer: FeatureLayer = null;

    async svgRender(graphic: __esri.Graphic, size: number): Promise<void> {
        if (this.view.zoom > 9) {
            graphic.symbol = new SimpleMarkerSymbol({
                size: size,
                path: location,
                style: "path",
                color: graphic.attributes.color,
                outline: {
                    width: 0,
                    color: graphic.attributes.color
                }
            })
        } else {
            graphic.symbol = new SimpleMarkerSymbol({
                size: this.zoom > 4 ? 12 : 6,
                color: graphic.attributes.color,
                outline: {
                    width: 0,
                    color: graphic.attributes.color
                }
            })
        }
    }

    reRender() {
    }

    getFieldInfo(): any[] {
        return [
            {
                fieldName: "aqi",
                label: "AQI"
            },
            {
                fieldName: "pm25",
                label: "PM2.5"
            },
            {
                fieldName: "pm10",
                label: "PM10"
            },
            {
                fieldName: "so2",
                label: "SO2"
            },
            {
                fieldName: "no2",
                label: "NO2"
            },
            {
                fieldName: "co",
                label: "CO"
            },
            {
                fieldName: "o3",
                label: "O3"
            }
        ];
    }

    getMedia(): Object {
        return {
            type: "media",
            mediaInfos: [new ColumnChartMediaInfo({
                title: "大气污染物",
                value: {
                    colors: [
                        new Color({r: 220, g: 123, b: 4, a: 1}),
                        new Color({r: 229, g: 80, b: 53, a: 1})],
                    fields: ["aqi", "pm25", "pm10", "so2", "no2", "co", "o3"],
                }
            })]
        };
    }

    type: number;

    constructor() {
    }

    render(data: (Quality | Data)[], type: RenderType): void {
        console.log(data, type)
    }

    resolveGrade(data: Quality, type: RenderType): GradeObject {
        // 如果不为aqi则进行获取
        let gradeObject;
        if (type == RenderType.AQI) {
            gradeObject = Grade.getAqiByValue(Number(data?.aqi))
        } else {
            gradeObject = Grade.getGradeByLevel(data?.[`${type}Level`]);
        }
        return gradeObject;
    }
}

export class ProvinceRender extends BaseRender {
    readonly type = 0;

    render(data: (Quality & Province)[], type: RenderType) {
        //清除原有图层
        // 渲染逻辑
        // 省区渲染逻辑
        // 遍历省区数据 获取对应等级
        for (let featuresKey of china.features) {
            // 获取边界
            let provinceData = data.filter((item) => item.provinceCode == featuresKey.properties.adcode).pop();
            let gradeObject = this.resolveGrade(provinceData, type)
            let geometry = featuresKey.geometry.coordinates.map((item: any) => {
                return item[0]
            })

            let color = gradeObject?.color ?? "#808080";
            let level = gradeObject ? gradeObject.level : 0;
            //绘制省区边界
            let graphic = new Graphic({
                geometry: new Polygon({rings: geometry}),
                popupTemplate: {
                    title: "{title}",
                    content: [
                        // this.getMedia()
                    ],
                    //停靠
                    actions: null,
                    overwriteActions: true,
                    fieldInfos: this.getFieldInfo()
                },
                symbol: new SimpleFillSymbol({
                    color: color,
                    outline: {
                        width: 1,
                        color: "#fff"
                    },
                }),
                attributes: Object.assign({
                    level: level,
                    color: color,
                    id: provinceData?.id,
                    type: RenderTypeName.province,
                    title: provinceData?.provinceName,
                    jx: provinceData?.provinceJc
                }, {aqi: "0", pm25: "0", pm10: "0", so2: "0", no2: "0", co: "0", o3: "0"}, provinceData)
            })
            this.graphicLayer.add(graphic)
        }
        //绘制图例
    }

}

export class AreaRender extends BaseRender {
    readonly type = 1;

    render(data: (Quality & Area)[], type: RenderType) {
        //移除所有图层
        // 渲染逻辑
        //获取市区数据
        for (let area of data) {
            let gradeObject = this.resolveGrade(area, type)
            let color = gradeObject ? gradeObject.color : "#808080"
            let level = gradeObject ? gradeObject.level : 0
            let graphic = new Graphic({
                geometry: new Point({longitude: Number(area.longitude), latitude: Number(area.latitude)}),
                symbol: new SimpleMarkerSymbol({
                    color: color,
                    size: Common.getViewPointSize(0.4),
                    outline: {
                        color: color,
                        width: 1
                    }
                }),
                attributes: Object.assign(area, {
                    level: level,
                    color: color,
                    type: RenderTypeName.area,
                    id: area.cityCode,
                    title: area.cityName,
                    ratio: 0,
                }),
                popupTemplate: {
                    title: "{title}",
                    content: [
                        // this.getMedia()
                    ],
                    fieldInfos: this.getFieldInfo(),
                },
            })
            //记录污染图形
            this.graphicLayer.add(graphic)
        }
    }

}

export class StationRender extends BaseRender {

    readonly type = 2;

    render(data: Data[], type: RenderType) {
        this.graphicLayer.removeAll()
        // 渲染逻辑
        for (let station of data) {
            let objectValue = station.stationQuality ? station.stationQuality[type.toString()] : null
            let gradeObject = Grade.getAqiByValue(objectValue)
            let color = gradeObject ? gradeObject.color : "#808080"
            let level = gradeObject ? gradeObject.level : 0
            let graphic = new Graphic({
                geometry: new Point({longitude: Number(station.longitude), latitude: Number(station.latitude)}),
                attributes: Object.assign({
                    level: level,
                    color: color,
                    id: station.stationCode,
                    type: RenderTypeName.station,
                    title: station.positionName,
                }, station.stationQuality),
                popupTemplate: {
                    title: station.positionName,
                    content: [
                        // this.getMedia()
                    ],
                    //停靠
                    actions: null,
                    overwriteActions: true,
                    fieldInfos: this.getFieldInfo()
                },
            })
            this.svgRender(graphic, 20)
            this.graphicLayer.add(graphic)
        }
    }

    reRender() {
        for (let graphic of this.graphicLayer.graphics) {
            this.svgRender(graphic, 20)
        }
    }
}

/**
 * 图标渲染
 */
export interface ChartStrategy {
    render(attributes: Attribute, type: number, value: RenderType, data: Quality[], change: RenderChange): void;

    renderHistory(element: HTMLCollectionOf<Element>, attributes: Attribute, value: RenderType, data: Quality[])

    renderSize(element: HTMLCollectionOf<Element>);
}

export class BaseChartStrategy implements ChartStrategy {
    constructor() {
    }

    renderHistory(element: HTMLCollectionOf<Element>, attributes: Attribute, value: RenderType, quality: Quality[]) {
        let data = quality ?? []
        let xTime = data.map(da => {
            let time = new Date(da.timestamp);
            return time.toLocaleDateString("zh-CN", {
                hour: "2-digit",
                minute: "2-digit",
                second: "2-digit",
                hour12: false
            })
        })
        this.renderFirst(element, attributes)

        this.renderThird(element, xTime, attributes, value, data)
        this.renderSeventh(element, data)
        this.renderFifth(element, data)
    }

    renderSize(element: HTMLCollectionOf<Element>) {
        let firstDom = element[0] as HTMLElement
        let first = echarts.getInstanceByDom(firstDom) ?? echarts.init(firstDom)
        first.setOption({
            title: {
                textStyle: {
                    fontSize: Common.getViewPointSize(1)
                },
            },
            series: [
                {
                    progress: {
                        width: Common.getViewPointSize(0.5),
                        itemStyle: {
                            borderWidth: Common.getViewPointSize(0.35),
                        }
                    },
                    axisLine: {
                        lineStyle: {
                            width: Common.getViewPointSize(0.5)
                        }
                    },
                    data: [
                        Common.deepMerge(first.getOption().series[0].data[0], {
                            title: {
                                fontSize: Common.getViewPointSize(1),
                            },
                            detail: {
                                fontSize: Common.getViewPointSize(1.5)
                            }
                        })
                    ]
                }
            ]
        })

        let secondDom = element[1] as HTMLElement
        let second = echarts.getInstanceByDom(secondDom) ?? echarts.init(secondDom)

        let thirdDom = element[2] as HTMLElement
        let third = echarts.getInstanceByDom(thirdDom) ?? echarts.init(thirdDom)
        third.setOption({
            title: {
                textStyle: {
                    fontSize: Common.getViewPointSize(1)
                }
            },
            visualMap: {
                itemWidth: Common.getViewPointSize(1.4),
                itemHeight: Common.getViewPointSize(1),
                itemGap: Common.getViewPointSize(0.7),
                textStyle: {
                    fontSize: Common.getViewPointSize(0.8)
                }
            },
        })


        let fourthDom = element[4] as HTMLElement
        let fourth = echarts.getInstanceByDom(fourthDom) ?? echarts.init(fourthDom)
        fourth.setOption({
            title: [
                {
                    textStyle: {
                        fontSize: Common.getViewPointSize(1),
                    },
                },
            ],
            series: [
                {
                    label: {
                        fontSize: Common.getViewPointSize(0.7),
                    },
                },
            ]
        })
        let fifthDom = element[5] as HTMLElement
        let fifth = echarts.getInstanceByDom(fifthDom) ?? echarts.init(fifthDom)
        fifth.setOption({
            title: [
                {
                    textStyle: {
                        fontSize: Common.getViewPointSize(1),
                    },
                },
                {
                    textStyle: {
                        fontSize: Common.getViewPointSize(0.8),
                    },
                }
            ],
            series: {
                label: {
                    fontSize: Common.getViewPointSize(0.7),
                },
            },
        })

        let sixthDom = element[6] as HTMLElement
        let sixth = echarts.getInstanceByDom(sixthDom) ?? echarts.init(sixthDom)

        let seventhDom = element[7] as HTMLElement
        let seventh = echarts.getInstanceByDom(seventhDom) ?? echarts.init(seventhDom)
        seventh.setOption({
            title: {
                textStyle: {
                    fontSize: Common.getViewPointSize(1)
                }
            },
        });
    }

    render(attributes: Attribute, type: number, value: RenderType, data: Quality[], change: RenderChange): void {
        console.log(attributes, type, value, data, change)
    }

    renderFirst(element: HTMLCollectionOf<Element>, attributes: Attribute) {
        //绘制第一个
        let first = element[0] as HTMLElement;
        let instanceByFirst = echarts.getInstanceByDom(first)
        let firstChart: EChartsType = instanceByFirst ?? echarts.init(first)
        let colorList = []
        let AQI = Grade.getPollutionLevel(RenderType.AQI)
        let max = Grade.getPollutionLevelByValue(attributes.aqi, AQI);
        for (let item of AQI) {
            if (!max) break
            colorList.push({offset: item.level / max?.level, color: item.color})
            if (item.level === max.level) break
        }
        let gradeObject = Grade.getAqiByValue(attributes.aqi);
        firstChart.setOption({
            title: {
                text: "AQI指数",
                textStyle: {
                    color: "rgba(159,206,255,0.7)",
                    fontSize: Common.getViewPointSize(1)
                },
                left: "center",
                top: "20%"
            },
            series: [
                {
                    type: 'gauge',
                    min: 0,
                    max: 500,
                    pointer: {
                        show: false
                    },
                    radius: "95%",
                    progress: {
                        width: Common.getViewPointSize(0.5),
                        show: true,
                        roundCap: true,
                        itemStyle: {
                            borderColor: "rgba(255,255,255,0.5)",
                            borderWidth: Common.getViewPointSize(0.35),
                            color: {
                                type: 'linear',
                                x: 0,
                                y: 1,
                                x2: 1,
                                y2: 0,
                                colorStops: colorList,
                            }
                        }
                    },
                    axisLine: {
                        roundCap: true,
                        lineStyle: {
                            width: Common.getViewPointSize(0.5)
                        }
                    },
                    splitLine: {
                        show: false
                    },
                    axisTick: {
                        show: false
                    },
                    axisLabel: {
                        show: false
                    },
                    data: [
                        {
                            value: attributes?.aqi ?? 0,
                            name: gradeObject?.label,
                            title: {
                                show: true,
                                fontSize: Common.getViewPointSize(1),
                                color: Common.isDarkByHexOrRgb(gradeObject?.color) ? "#fff" : "#000",
                                borderWidth: 1,
                                padding: [2, 10],
                                offsetCenter: ["0", "40%"],
                                borderRadius: 50,
                                backgroundColor: gradeObject?.color
                            },
                            detail: {
                                valueAnimation: true,
                                color: '#fff',
                                offsetCenter: ["0", "0"],
                                fontSize: Common.getViewPointSize(1.5)
                            },
                        }
                    ]
                }
            ]
        })
    }

    renderSixth(element: HTMLCollectionOf<Element>, yList: string[], seriesList: number[], index: number) {
        let fourth = element[6] as HTMLElement
        let fourthInstance = echarts.getInstanceByDom(fourth);
        let fourthChart: EChartsType = fourthInstance ?? echarts.init(fourth)
        fourthChart.setOption({
            tooltip: {
                trigger: 'axis',
            },
            grid: {
                top: 0,
                bottom: 0,
                containLabel: true
            },
            xAxis: {
                type: 'value',
                boundaryGap: [0, 0.01],
                axisLabel: {
                    color: "#9FCEFF"
                }
            },
            yAxis: {
                type: 'category',
                data: yList,
                axisLabel: {
                    color: "#9FCEFF"
                },
            },
            dataZoom: [
                {
                    type: "inside",
                    orient: 'vertical',
                    startValue: seriesList.length - index,
                    minValueSpan: 6,
                    maxValueSpan: 6,
                }
            ],
            series: [
                {
                    type: 'bar',
                    data: seriesList,
                    itemStyle: {
                        color: (params) => {
                            let byValue = Grade.getAqiByValue(params.value);
                            return byValue?.color;
                        }
                    }
                }
            ]
        })
    }

    renderThird(element: HTMLCollectionOf<Element>, xTime: string[], attributes: Attribute, value: RenderType, data: Quality[]) {
        // 绘制第四个
        let myChart: EChartsType;
        let fifth = element[2];
        let instanceByDom = echarts.getInstanceByDom(fifth as HTMLElement);
        myChart = instanceByDom ?? echarts.init(fifth as HTMLElement)
        myChart.setOption({
            title: {
                text: `${attributes.title} ${value.toUpperCase()}`,
                left: 4,
                top: 4,
                textStyle: {
                    color: '#9FCEFF',
                    fontSize: Common.getViewPointSize(1)
                }
            },
            tooltip: {
                trigger: 'axis',
            },
            grid: {
                right: '30%',
                left: 0,
                bottom: 0,
                containLabel: true
            },
            xAxis: {
                data: xTime
            },
            yAxis: {},
            toolbox: {
                right: 10,
                feature: {
                    restore: {},
                    saveAsImage: {}
                }
            },
            dataZoom: [
                {
                    type: 'inside'
                }
            ],
            visualMap: {
                left: "70%",
                top: "15%",
                itemWidth: Common.getViewPointSize(1.4),
                itemHeight: Common.getViewPointSize(1),
                pieces: Grade.getPollutionLevel(RenderType.AQI).filter(item => item.level != 0).map(item => {
                    let items: any = {};
                    if (item.valueRight) {
                        items.lte = item.valueRight
                    }
                    items.gt = item.valueLeft
                    items.color = item.color
                    return items
                }),
                itemGap: Common.getViewPointSize(0.7),
                outOfRange: {
                    color: '#fff'
                },
                textStyle: {
                    color: "#fff",
                    fontSize: Common.getViewPointSize(0.8)
                }
            },
            series: {
                name: `${attributes.title} ${value.toUpperCase()}`,
                type: 'line',
                data: Grade.getIAQIExtend(data, value).map(item => {
                    return (item == 0 || item == "0") ? null : item
                }),
                // markLine: {
                //     silent: true,
                //     lineStyle: {
                //         color: '#fff'
                //     },
                //     data: gradeOption.map(s => {
                //         return {yAxis: s["lte"] ?? s["gt"]}
                //     })
                // },
            }
        })
    }

    renderFifth(element: HTMLCollectionOf<Element>, data: Quality[]) {
        //绘制第五个
        let fifth = element[4] as HTMLElement;
        let sixth = element[5] as HTMLElement;
        let myChart5 = echarts.getInstanceByDom(fifth) ?? echarts.init(fifth);
        let myChart6 = echarts.getInstanceByDom(sixth) ?? echarts.init(sixth);
        //数据处理
        let healthDays = data.map(item => {
            return Grade.getAqiByValue(Number(item.aqi))
        }).reduce((acc, num) => {
            // 如果acc（累加器）中没有这个数的计数，则初始化为1
            // 否则，在已有的计数上加1
            acc[num?.level] = (acc[num?.level] || 0) + 1;
            return acc;
        }, {})
        let gradeObjects = Grade.getPollutionLevel(RenderType.AQI);
        let allDays = gradeObjects.map(grade => {
            let value = healthDays[grade.level]
            let number = value / data.length * 100;
            return {name: grade.label, value: Number(number.toFixed(2))}
        }).filter(item => !Number.isNaN(item.value))
        let reduce = allDays.reduce((a, b) => {
            return a.value > b.value ? a : b
        }, {});
        myChart5.setOption({
            tooltip: {
                trigger: "item"
            },
            title: [
                {
                    text: "污染状况",
                    left: "center",
                    textStyle: {
                        fontSize: Common.getViewPointSize(1),
                        color: "#9FCEFF"
                    },
                },
                {
                    text: reduce?.name ? `${reduce.name} 占比 ${reduce.value}%` : "暂无信息",
                    left: "center",
                    top: "15%",
                    textStyle: {
                        fontSize: Common.getViewPointSize(0.8),
                    },
                    padding: [5, 10],
                    backgroundColor: "#9FCEFF",
                    borderRadius: 50
                }
            ],
            series: [
                {
                    name: '天气比例',
                    type: 'pie',
                    radius: '35%',
                    center: ['50%', '70%'],
                    data: allDays,
                    label: {
                        fontSize: Common.getViewPointSize(0.7),
                        color: "#fff",
                    },
                    tooltip: {
                        formatter: "{b} : {c}%",
                        position: "right"
                    }
                },
            ]
        })
        //首要污染物只包含aqi>50的
        let result = {}
        let pollution = data.filter(item => Number(item.aqi) > 50)
        pollution.forEach(item => {
            let temp = quality.filter(item => {
                return item != "aqi"
            }).map(s => {
                return {name: s, value: Grade.getIAQI(item, s)}
            }).reduce((a, b) => {
                if (a.value > b.value) {
                    return a;
                } else {
                    return b;
                }
            })
            result[temp.name] = (result[temp.name] || 0) + 1
        })
        let pollutions = Object.keys(result).map(item => {
            return {name: item, value: (result[item] / pollution.length * 100).toFixed(2)}
        })
        let mainPollution = pollutions.reduce((a, b) => {
            if (a.value > b.value) {
                return a;
            }
            return b;
        }, {name: null, value: null})
        myChart6.setOption({
            tooltip: {
                trigger: "item"
            },
            title: [
                {
                    text: "首要污染物",
                    left: "center",
                    textStyle: {
                        fontSize: Common.getViewPointSize(1),
                        color: "#9FCEFF"
                    },
                },
                {
                    text: mainPollution.name ? `${mainPollution?.name} 占比:${mainPollution?.value}%` : "暂无首要污染物",
                    left: "center",
                    top: "15%",
                    textStyle: {
                        fontSize: Common.getViewPointSize(0.8),
                    },
                    padding: [5, 10],
                    backgroundColor: "#9FCEFF",
                    borderRadius: 50
                }
            ],
            series: {
                name: '主要污染物占比',
                type: 'pie',
                radius: '35%',
                center: ['50%', '70%'],
                data: pollutions,
                label: {
                    fontSize: Common.getViewPointSize(0.7),
                    color: "#fff",
                },
                tooltip: {
                    formatter: "{a}<br/>{b} : {d}%",
                    position: "left"
                }
            },
        })
    }

    renderSeventh(element: HTMLCollectionOf<Element>, data: Quality[]) {
        //绘制第二个
        let myChart2: EChartsType;
        let sixth = element[7];
        let instanceByDom1 = echarts.getInstanceByDom(sixth as HTMLElement);
        myChart2 = instanceByDom1 ?? echarts.init(sixth as HTMLElement);
        // 将浓度转化为分值 获取平均值最大为500
        let result = quality.map(i => {
            let numbers = Grade.getIAQIExtend(data, i).filter(item => item);
            return numbers.reduce((a, b) => a + b, 0) / numbers.length;
        })
        result[0] = Math.max(...result)
        let option = {
            title: {
                text: 'AQI - 分布图',
                left: 'left',
                textStyle: {
                    color: '#9FCEFF',
                    fontSize: Common.getViewPointSize(1)
                }
            },
            radar: {
                indicator: [
                    {name: 'AQI', max: 500},
                    {name: 'PM2.5', max: 500},
                    {name: 'PM10', max: 500},
                    {name: 'SO2', max: 500},
                    {name: 'NO2', max: 500},
                    {name: 'CO', max: 500},
                    {name: "O3", max: 500}
                ],
                shape: 'circle',
                splitNumber: 5,
                axisName: {
                    color: 'rgb(238, 197, 102)'
                },
                splitLine: {
                    lineStyle: {
                        color: [
                            'rgba(238, 197, 102, 0.1)',
                            'rgba(238, 197, 102, 0.2)',
                            'rgba(238, 197, 102, 0.3)',
                            'rgba(238, 197, 102, 0.4)',
                            'rgba(238, 197, 102, 0.6)',
                            'rgba(238, 197, 102, 0.8)',
                            'rgba(238, 197, 102, 1)'
                        ].reverse()
                    }
                },
                splitArea: {
                    show: false
                },
                nameGap: 10,
                axisLine: {
                    lineStyle: {
                        color: 'rgba(238, 197, 102, 0.5)'
                    }
                }
            },
            series: [
                {
                    name: 'Beijing',
                    type: 'radar',
                    lineStyle: {
                        width: 1,
                    },
                    data: [result],
                    symbol: 'none',
                    itemStyle: {
                        color: '#F9713C'
                    },
                    areaStyle: {
                        opacity: 0.1
                    },
                }
            ]
        };
        myChart2.setOption(option)
    }

    renderSecond(element: HTMLCollectionOf<Element>, data: Base[], value: RenderType) {
        let second = element[1] as HTMLElement
        let instanceByDom = echarts.getInstanceByDom(second);
        let myChart = instanceByDom ?? echarts.init(second);
        let xData = []
        for (let i = 0; i < 48; i++) {
            xData.push(i)
        }
        let yData = data.map(item => {
            return {
                itemStyle: {color: Grade.getAqiByValue(Grade.getIAQI(item, value)).color},
                value: item[value]
            }
        })
        myChart.setOption({
            grid: {
                bottom: 0,
                left: 0,
                top: "5%",
                right: "2%",
                containLabel: true
            },
            xAxis: {
                axisLabel: {
                    color: '#fff'
                },
                axisTick: {
                    show: false
                },
                axisLine: {
                    show: false
                },
                data: xData,
                z: 10
            },
            yAxis: {
                axisLine: {
                    show: false
                },
                axisTick: {
                    show: false
                },
                axisLabel: {
                    color: '#999'
                }
            },
            tooltip: {},
            dataZoom: [
                {
                    type: 'inside'
                }
            ],
            series: [
                {
                    type: 'bar',
                    showBackground: true,
                    itemStyle: {
                        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                            {offset: 0, color: '#83bff6'},
                            {offset: 0.5, color: '#188df0'},
                            {offset: 1, color: '#188df0'}
                        ])
                    },
                    emphasis: {
                        itemStyle: {
                            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                                {offset: 0, color: '#2378f7'},
                                {offset: 0.7, color: '#2378f7'},
                                {offset: 1, color: '#83bff6'}
                            ])
                        }
                    },
                    markArea: {
                        data: [
                            [
                                {
                                    xAxis: 24
                                },
                                {
                                    xAxis: 48
                                }
                            ]
                        ],
                        emphasis: {
                            disabled: true
                        },
                        itemStyle: {
                            color: "rgba(255, 255, 255, 0.5)"
                        }
                    },
                    data: yData
                }
            ]
        })
    }
}

/**
 * 省区图标渲染
 */
export class ProvinceChartStrategy extends BaseChartStrategy {

    /**
     * 绘制的部分有三个
     * 1. 当前的空气质量曲线以及主要的污染物
     * 2. 当前的省区下各市空气质量柱状图
     * 3. 当前的省区下各市的污染物分布
     * @param attributes
     * @param type 类型
     * @param value 渲染类型
     * @param data 融合数据
     * @param change
     */
    render(attributes: Attribute, type: number, value: RenderType, data: (Quality & Province)[], change: RenderChange) {
        let element = document.getElementsByClassName("echarts");

        if (change == RenderChange.SizeChange) {
            super.renderSize(element)
            return;
        }

        getProvinceHistory({id: attributes.id, type: type}).then(res => {
            super.renderHistory(element, attributes, value, res.data.data)
        })

        if (change == RenderChange.TargetChange) {
            getProvincePredict(attributes.id).then(res => {
                super.renderSecond(element, res.data.data, RenderType.AQI);
            })
            let yList = []
            let seriesList = []
            let i = data.length
            let index = 1
            data.sort((a, b) => Number(b[RenderType.AQI]) - Number(a[RenderType.AQI])).forEach(item => {
                yList.push(item.provinceName + `-${i}`)
                seriesList.push(item[value] ?? 0)
                if (item.id == attributes.id) index = i
                i--
            })
            super.renderSixth(element, yList, Grade.getIAQIExtend(data, RenderType.AQI), index)
        }

        //第六
        //绘制第一个
        if (change != RenderChange.TargetChange) return
        super.renderFirst(element, attributes)
    }
}

/**
 * 区域图表渲染
 */
export class AreaChartStrategy extends BaseChartStrategy {
    /**
     * 绘制市区的图像
     * @param attributes
     * @param type
     * @param value
     * @param data
     * @param change
     */
    render(attributes: Attribute, type: number, value: RenderType, data: (Quality & Area)[], change: RenderChange) {
        let element = document.getElementsByClassName("echarts");
        if (change == RenderChange.SizeChange) {
            super.renderSize(element)
            return;
        }
        getAreaHistory({id: attributes.id, type: type}).then(res => {
            super.renderHistory(element, attributes, value, res.data.data?.quality)
        })
        if (change == RenderChange.TargetChange) {
            getAreaPredict(attributes.id).then(res => {
                super.renderSecond(element, res.data.data, value)
            })
            //绘制第六个区域排名
            let yList = []
            let index = 1
            let i = data.length
            data.sort((a, b) => Number(b[RenderType.AQI]) - Number(a[RenderType.AQI])).forEach(item => {
                yList.push(item.cityName + `-${i}`)
                if (item.cityCode == attributes.id) index = i
                i--
            })
            super.renderSixth(element, yList, Grade.getIAQIExtend(data, RenderType.AQI), index)
        }

        if (change != RenderChange.TargetChange) return
        super.renderFirst(element, attributes)
    }
}

/**
 * 站点图表渲染
 */
export class StationChartStrategy extends BaseChartStrategy {
    render(attributes: Attribute, type: number, value: RenderType, data: (Data & Quality) [], change: RenderChange) {
        let element = document.getElementsByClassName("echarts");
        if (change == RenderChange.SizeChange) {
            super.renderSize(element)
            return;
        }
        getStationHistory({id: attributes.id, type: type}).then(res => {
            super.renderHistory(element, attributes, value, res.data.data)
        })
        //绘制第六个区域排名
        if (change == RenderChange.TargetChange) {
            getStationPredict(attributes.id).then(res => {
                super.renderSecond(element, res.data?.data ?? [], value)
            })
            let yList = []
            let seriesList = []
            let index = 1
            let i = data.length
            data.sort((a, b) => Number(b.stationQuality[RenderType.AQI]) - Number(a.stationQuality[RenderType.AQI])).forEach(item => {
                yList.push(item.positionName + `-${i}`)
                seriesList.push(item.stationQuality.aqi)
                if (item.stationCode == String(attributes.id)) index = i
                i--
            })
            super.renderSixth(element, yList, Grade.getIAQIExtend(data.map(item => item.stationQuality), RenderType.AQI), index)
        }
        if (change != RenderChange.TargetChange) return
        super.renderFirst(element, attributes)
    }
}

export class Context {

    private strategy: Render;
    private readonly graphicLayer: GraphicsLayer;
    private readonly map: ArcGISMap;
    private view: MapView;
    private _data: Quality[];
    /**
     * 展示地图数据
     */
    private chart: ChartStrategy;


    public set data(value: Quality[]) {
        this._data = value;
    }

    set setChart(value: ChartStrategy) {
        this.chart = value;
    }

    constructor(graphicLayer: __esri.GraphicsLayer, map: __esri.Map, view: __esri.MapView) {
        this.graphicLayer = graphicLayer;
        this.map = map;
        this.view = view;
    }

    // 设置渲染策略
    setRender(render: Render): void {
        render.map = this.map
        render.view = this.view
        render.graphicLayer = this.graphicLayer
        this.strategy = render;
    }

    public render(type: RenderType): void {
        console.assert(this.strategy != null, "请先设置渲染策略")
        this.graphicLayer.removeAll()
        this.strategy.render(this._data, type);
    }

    public setView(view: __esri.MapView): void {
        this.view = view;
    }

    public reRender(): void {
        Promise.resolve(this.strategy.reRender())
    }

    public renderData(attributes: Attribute, type: number, value: RenderType, data: Quality[], change: RenderChange): void {
        this.chart.render(attributes, type, value, data, change)
    }
}


/**
 * 对大气不同污染物进行分类
 */
export class Grade {

    private static map = new Map<RenderType | string, GradeObject[]>();

    static {
        this.map.set(RenderType.AQI, [
            {
                label: '优',
                color: '#00e400',
                level: 1,
                valueLeft: 0,
                valueRight: 50,
            },
            {
                label: '良',
                color: '#ffff00',
                level: 2,
                valueLeft: 50,
                valueRight: 100,
            },
            {
                label: '轻度污染',
                color: '#ff7e00',
                level: 3,
                valueLeft: 100,
                valueRight: 150,
            },
            {
                label: '中度污染',
                color: '#ff0000',
                level: 4,
                valueLeft: 150,
                valueRight: 200,
            },
            {
                label: '重度污染',
                color: '#99004c',
                level: 5,
                valueLeft: 200,
                valueRight: 300,
            },
            {
                label: '严重污染',
                color: '#7e0023',
                level: 6,
                valueLeft: 300,
                valueRight: 500,
            },
            {
                label: "无信息",
                color: "#808080",
                level: 0,
                valueLeft: 0,
                valueRight: 0,
            },
        ])
    }

    // 获取污染等级
    public static getPollutionLevel(key: RenderType | string): GradeObject[] {
        return Common.deepCopy(this.map.get(key));
    }

    public static getPollutionLevelByValue(value: number, grade: GradeObject[]): GradeObject {
        if (value == null || String(value) == "0" || !value) return null
        // 获取对应等级
        let pop = grade.filter((item) => {
            return value > item.valueLeft && value <= item.valueRight
        }).pop();
        return pop ?? grade[grade.length - 1];
    }

    public static getAqiByValue(value: number): GradeObject {
        return this.getPollutionLevelByValue(value, this.getPollutionLevel(RenderType.AQI));
    }

    public static getGradeByLevel(level: number) {
        let objects = Grade.getPollutionLevel(RenderType.AQI);
        return objects.filter((item) => {
            return level == item.level
        }).pop()
    }


    static list = {
        "so2": [0, 150, 500, 650, 800],
        "so2_24": [0, 50, 150, 475, 800, 1600, 2100, 2620],
        "no2": [0, 100, 200, 700, 1200, 2340, 3090, 3840],
        "pm10_24": [0, 50, 150, 250, 350, 420, 500, 600],
        "pm25_24": [0, 35, 75, 115, 150, 250, 350, 500],
        "co": [0, 5, 10, 35, 60, 90, 120, 150],
        "o3_8": [0, 100, 160, 215, 265, 800],
        "o3": [0, 160, 200, 300, 400, 800, 1000, 1200],
        "aqi": [0, 50, 100, 150, 200, 300, 400, 500]
    };

    static strategy = {
        "so2": {
            field: ["so2", "soH"],
            level: ["so2", "so2_24"]
        },
        "no2": {
            field: ["no2"],
            level: ["no2"]
        },
        "pm10": {
            field: ["pm10H"],
            level: ["pm10_24"]
        },
        "pm25": {
            field: ["pm25H"],
            level: ["pm25_24"]
        },
        "co": {
            field: ["co"],
            level: ["co"]
        },
        "o3": {
            field: ["o3"],
            level: ["o3"]
        },
    }

    public static getIAQICommon(value: number, field: string) {
        let element = this.list[field];
        let aqi = this.list.aqi;
        for (let i = 0; i < element.length - 1; i++) {
            let aqi_l = aqi[i];
            let aqi_h = aqi[i + 1];
            let bp = element[i]
            let bp_h = element[i + 1]
            if (value > bp && value <= bp_h) {
                return (aqi_h - aqi_l) / (bp_h - bp) * (value - bp) + aqi_l;
            }
        }
        return 0;
    }


    public static getIAQIExtend(data: Quality[], value: RenderType | string): number[] {
        if (value == RenderType.AQI) {
            return data.map(item => Number(item.aqi));
        }
        let element = Grade.strategy[value];
        let iAqis = [];
        data.forEach(item => {
            let iAqi = 0;
            for (let i = 0; i < element.field.length; i++) {
                let itemElement = item[element.field[i]];
                if (!itemElement) {
                    break;
                }
                iAqi = Grade.getIAQICommon(itemElement, element.level[i]);
                if (i == element.field.length - 1 && !iAqi) {
                    iAqis.push(500)
                }
                if (iAqi) {
                    break;
                }
            }
            iAqis.push(Math.ceil(iAqi))
        })
        return iAqis;
    }

    public static getIAQI(data: Quality | Base, value: RenderType | string) {
        if (value == RenderType.AQI) {
            return Number(data.aqi)
        }
        let element = Grade.strategy[value];
        let iAqi = 0;
        for (let i = 0; i < element.field.length; i++) {
            let itemElement = data[element.field[i]];
            if (!itemElement) {
                break;
            }
            iAqi = Grade.getIAQICommon(itemElement, element.level[i]);
            if (i == element.field.length - 1 && !iAqi) {
                return 500;
            }
            if (iAqi) {
                break;
            }
        }
        return Math.ceil(iAqi);
    }
}


